package com.smartstate.iot.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.smartstate.iot.config.redis.RedisCacheUtils;
import com.smartstate.iot.config.redis.RedisService;
import com.smartstate.iot.dto.PageDTO;
import com.smartstate.iot.entity.IotDataDistribution;
import com.smartstate.iot.entity.TopicConfig;
import com.smartstate.iot.entity.TopicLog;
import com.smartstate.iot.entity.vo.HandOutVo;
import com.smartstate.iot.entity.vo.PageResultDto;
import com.smartstate.iot.mapper.IotDataDistributionMapper;
import com.smartstate.iot.mapper.TopicLogMapper;
import com.smartstate.iot.mapper.TopicMapper;
import com.smartstate.iot.service.DataDistributionService;
import com.smartstate.iot.entity.vo.DataVo;
import com.smartstate.iot.vo.ResultVO;
import com.smartstate.iot.vo.TopicUpVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@Service
@Transactional
public class DataDistributionServiceImpl implements DataDistributionService {

    @Resource
    RedisTemplate redisTemplate = RedisService.redis;
    @Autowired
    private RedisService redisService;
    @Autowired
    private IotDataDistributionMapper dataDistributionMapper;
    @Autowired
    private TopicLogMapper topicLogMapper;
    @Autowired
    private RedisCacheUtils cacheUtils;
    @Autowired
    private TopicMapper mapper;

    private static final int MANUAL_OPERATION = 1;
    private static final int AUTOMATIC = 0;

    /**
     * 分发数据列表展示
     *
     * @param dto
     * @return
     */
    @Override
    public ResultVO<PageResultDto> list(PageDTO dto) {
        //当前页
        long page = dto.getPage();
        //每页条数
        long pageSize = dto.getSize();

        Map<String, String> map = (Map) dto.getDto();
        String dataId = map.get("dataId");
        //  查询数据库，所有分发记录
        List<IotDataDistribution> iotDataDistributions = dataDistributionMapper.selectList(new LambdaQueryWrapper<IotDataDistribution>());
        //  查询Redis中所有的key
        ArrayList<String> keys = getKeys();
        //  查询redis，所有数据
        //  如果是条件查询，根据dataId查询
        if (dataId != null && !dataId.equals("")) {
            ArrayList<DataVo> dataVos = new ArrayList<>();
            int index = dataId.indexOf(".");
            if (index == -1) {
                //  模糊搜索
                for (String key : keys) {
                    Map<String, Object> cacheMap = redisService.getCacheMap(key);
                    int index1 = key.lastIndexOf(":");
                    String deviceId = key.substring(index1 + 1);
                    //  与设备比较
                    if (deviceId.contains(dataId)) {
                        for (Map.Entry<String, Object> stringObjectEntry : cacheMap.entrySet()) {
                            if ("ip".equals(stringObjectEntry.getKey()) || "type".equals(stringObjectEntry.getKey()) || "port".equals(stringObjectEntry.getKey())) {
                                continue;
                            }
                            DataVo dataVo = new DataVo();
                            String newDataId = "";
                            newDataId = getNewDataId(key, stringObjectEntry, dataVo, newDataId);
                            setType(dataVos, dataVo, newDataId);
                        }
                    } else {
                        //  与设备属性比较
                        for (Map.Entry<String, Object> stringObjectEntry : cacheMap.entrySet()) {
                            if ("ip".equals(stringObjectEntry.getKey()) || "type".equals(stringObjectEntry.getKey()) || "port".equals(stringObjectEntry.getKey())) {
                                continue;
                            }
                            if (stringObjectEntry.getKey().contains(dataId)) {
                                DataVo dataVo = new DataVo();
                                String newDataId = "";
                                newDataId = getNewDataId(key, stringObjectEntry, dataVo, newDataId);
                                setType(dataVos, dataVo, newDataId);
                            }
                        }
                    }
                }
                //  判断是否存在数据
                if (dataVos.size() == 0) {
                    return ResultVO.fail("暂无数据！");
                } else {
                    //  存在数据，进行分页
                    PageResultDto pageResultDto = new PageResultDto();
                    List<List<DataVo>> pageData = getPageData(dataVos, (int) pageSize);
                    pageResultDto.setResult(pageData.get((int) (page - 1)));
                    pageResultDto.setTotal(dataVos.size());
                    int totalPageSize = (int) Math.ceil((double) dataVos.size() / pageSize);
                    pageResultDto.setTotalPageSize(totalPageSize);
                    return ResultVO.ok(pageResultDto);
                }
            } else {
                //  精确搜索
                String[] split = dataId.toString().split("\\.");
                if (split.length != 2) {
                    return ResultVO.fail("请输入正确的dataId!");
                }
                Map<String, Object> cacheMap = redisService.getCacheMap(split[0]);
                if (cacheMap == null) {
                    return ResultVO.fail("搜索目标不存在!");
                }
                ArrayList<DataVo> dataVos1 = new ArrayList<>();
                boolean flag = true;
                for (Map.Entry<String, Object> stringObjectEntry : cacheMap.entrySet()) {
                    DataVo dataVo = new DataVo();
                    dataVo.setDataId(dataId);
                    if (!stringObjectEntry.getKey().equals(split[1])) {
                        continue;
                    } else {
                        flag = false;
                    }
                    for (IotDataDistribution s : iotDataDistributions) {
                        if (s.getAttributeType() == 1 && dataId.equals(s.getDistributionTarget())) {
                            dataVo.setAttributeType(MANUAL_OPERATION);
                            dataVo.setPrimaryData(s.getDataId());
                            dataVo.setWeight(s.getWeight());
                        }
                    }
                    dataVos1.add(dataVo);
                }
                if (flag) {
                    return ResultVO.fail("搜索目标不存在!");
                }
                List<List<DataVo>> pageData = getPageData(dataVos1, (int) pageSize);
                PageResultDto pageResultVo = new PageResultDto();
                pageResultVo.setResult(pageData.get((int) page - 1));
                pageResultVo.setTotal(dataVos1.size());
                int totalPageSize = (int) Math.ceil((double) dataVos1.size() / pageSize);
                pageResultVo.setTotalPageSize(totalPageSize);
                return ResultVO.ok(pageResultVo);
            }
        } else {
            //  dataId不存在，查询所有
            ArrayList<DataVo> dataVos = new ArrayList<>();
            List<String> targetAttributes = new ArrayList<>();
            for (String key : keys) {
                int index = key.lastIndexOf(":");
//                String[] split = key.split(":");
                Map<String, Object> cacheMap = redisService.getCacheMap(key);
                for (Map.Entry<String, Object> stringObjectEntry : cacheMap.entrySet()) {
//                    String targetAttribute = split[1] + "." + stringObjectEntry.getKey();
                    if ("ip".equals(stringObjectEntry.getKey()) || "type".equals(stringObjectEntry.getKey()) || "port".equals(stringObjectEntry.getKey())) {
                        continue;
                    }
                    String targetAttribute = key.substring(index + 1) + "." + stringObjectEntry.getKey();
                    targetAttributes.add(targetAttribute);
                }
            }
            for (String targetAttribute : targetAttributes) {
                DataVo dataVo = new DataVo();
                String[] split = targetAttribute.split("\\.");
                if (split.length > 0) {
                    dataVo.setDataId(targetAttribute);
                    for (IotDataDistribution s : iotDataDistributions) {
                        if (s.getAttributeType() == 1 && targetAttribute.equals(s.getDistributionTarget())) {
                            dataVo.setAttributeType(MANUAL_OPERATION);
                            dataVo.setPrimaryData(s.getDataId());
                            dataVo.setWeight(s.getWeight());
                        }
                    }
                    dataVos.add(dataVo);
                }
            }
            if (pageSize == 0) {
                pageSize = 10;
            }
            List<List<DataVo>> pageData = getPageData(dataVos, (int) pageSize);
            PageResultDto pageResultVo = new PageResultDto();
            if (page == 0) {
                page = 1;
            }
            if (pageData != null && pageData.size() != 0) {
                pageResultVo.setResult(pageData.get((int) page - 1));
                pageResultVo.setTotal(dataVos.size());
                int totalPageSize = (int) Math.ceil((double) dataVos.size() / pageSize);
                pageResultVo.setTotalPageSize(totalPageSize);
                return ResultVO.ok(pageResultVo);
            } else {
                return ResultVO.fail("暂无数据");
            }
        }
    }

    private String getNewDataId(String key, Map.Entry<String, Object> stringObjectEntry, DataVo dataVo, String newDataId) {
        int index1 = key.lastIndexOf(":");
        if (index1 != -1) {
            newDataId = key.substring(index1 + 1) + "." + stringObjectEntry.getKey();
            dataVo.setDataId(newDataId);
        }
        return newDataId;
    }

    private void setType(ArrayList<DataVo> dataVos, DataVo dataVo, String newDataId) {
        //  查询所有数据分发记录
        LambdaQueryWrapper<IotDataDistribution> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(IotDataDistribution::getAttributeType, 1);
        List<IotDataDistribution> dataDistributions = dataDistributionMapper.selectList(queryWrapper);
        if (dataDistributions.size() > 0) {
            //  遍历数据分发记录
            for (IotDataDistribution dataDistribution : dataDistributions) {
                if (dataDistribution.getDistributionTarget().equals(newDataId)) {
                    //  如果有分发记录，设置为手动
                    dataVo.setAttributeType(MANUAL_OPERATION);
                    dataVo.setWeight(dataDistribution.getWeight());
                    dataVo.setPrimaryData(dataDistribution.getDataId());
                    dataVos.add(dataVo);
                }
            }
            //  遍历完成，没有分发记录
            if (dataVo.getPrimaryData() == null) {
                dataVo.setAttributeType(AUTOMATIC);
                dataVos.add(dataVo);
            }
        } else {
            //  如果数据分发记录为空，则全为自动
            dataVo.setAttributeType(AUTOMATIC);
            dataVos.add(dataVo);
        }
    }

    /**
     * 获取redis中所有的key
     *
     * @return
     */
    public ArrayList<String> getKeys() {
        //  获取所有盒子
        List<TopicLog> topicLogs = topicLogMapper.getAllBox();
//        log.info(topicLogs.toString());
        TreeSet<String> boxName = new TreeSet<>();
        for (TopicLog topicLog : topicLogs) {
            boxName.add(topicLog.getDeviceId());
        }
        //  获取所有的key
        ArrayList<String> keys = new ArrayList<>();
        for (String logSet : boxName) {
            Set<String> tempKeys = redisTemplate.keys(logSet + ":*");
            if (tempKeys != null) {
                keys.addAll(tempKeys);
            }
        }
        return keys;
    }

    /**
     * 数据分发
     *
     * @param handOutVo
     */
    @Override
    public ResultVO<String> handOut(HandOutVo handOutVo) {
        try {
            String attributeName = "";
            String dataId = "";
//            //  将属性值从redis中查询出来
//            String handOutVoDataId = handOutVo.getDataId();
//            int index = handOutVoDataId.indexOf(".");
//            if (index == -1 ){
//                return ResultVO.fail("参数格式有误!");
//            }
//            String findKey = handOutVoDataId.substring(0, index);
//            String mapKey = handOutVoDataId.substring(index + 1);
//            Map<String, Object> cacheMap = redisService.getCacheMap(findKey);
//            String value = (String) cacheMap.get(mapKey);
//            //  需要分发的目标集合
//            List<DataVo> targetList = handOutVo.getTargetList();
//            IotDataDistribution dataDistribution = new IotDataDistribution();
//            dataDistribution.setDataId(handOutVo.getDataId());     //   原始数据
//            List<IotDataDistribution> dataDistributions = dataDistributionMapper.selectList(new LambdaQueryWrapper<IotDataDistribution>().eq(IotDataDistribution::getAttributeType, 1));
//            //  判断需要分发的目标是否已经被分发
//            for (DataVo dataVo : targetList) {
//                for (IotDataDistribution distribution : dataDistributions) {
//                    if (dataVo.getDataId().equals(distribution.getDistributionTarget())) {
//                        return ResultVO.fail(distribution.getDataId() + "已被分发至" + distribution.getDistributionTarget() + ",无法再次分发！");
//                    }
//                }
//            }
//            // TODO 遍历目标集合
//            for (DataVo dataVo : targetList) {
//
//            }


            //  将属性值从redis中查询出来
            String[] split = handOutVo.getDataId().split("\\.");
            if (split[0] != null && split[1] != "") {
                dataId = split[0];  //  原始数据设备名称
            }
            if (split[1] != null && split[1] != "") {
                attributeName = split[1];   //  原始设备属性名称
            }
            Map<String, Object> dataMap = redisService.getCacheMap(dataId);
            Object attributeValue = dataMap.get(attributeName);  //  属性值
            //  需要分发的目标集合
            List<DataVo> targetList = handOutVo.getTargetList();
            IotDataDistribution dataDistribution = new IotDataDistribution();
            dataDistribution.setDataId(handOutVo.getDataId());     //   原始数据
            List<IotDataDistribution> dataDistributions = dataDistributionMapper.selectList(new LambdaQueryWrapper<IotDataDistribution>().eq(IotDataDistribution::getAttributeType, 1));
            //  判断需要分发的目标是否已经被分发
            for (DataVo dataVo : targetList) {
                for (IotDataDistribution distribution : dataDistributions) {
                    if (dataVo.getDataId().equals(distribution.getDistributionTarget())) {
                        return ResultVO.fail(distribution.getDataId() + "已被分发至" + distribution.getDistributionTarget() + ",无法再次分发！");
                    }
                }
            }
            //  遍历目标集合
            loop:
            for (DataVo dataVo : targetList) {
                String[] hashAndKeys = dataVo.getDataId().split("\\.");
                String key = "";       //   目标属性名称
                String hash = "";       //  目标设备名称
                if (hashAndKeys[0] != null && hashAndKeys[1] != "") {
                    hash = hashAndKeys[0];
                }
                if (hashAndKeys[1] != null && hashAndKeys[1] != "") {
                    key = hashAndKeys[1];
                }
                HashMap<String, String> map = new HashMap<>();
                //  如果加权值为空或0，直接储存
                if (dataVo.getWeight() == null || dataVo.getWeight() == 0.0) {
                    map.put(key, String.valueOf(attributeValue));
                } else {
                    //  否则储存为属性值与加权值的乘积
                    map.put(key, String.valueOf(dataVo.getWeight() * Double.parseDouble(String.valueOf(attributeValue))));
                    dataDistribution.setWeight(dataVo.getWeight());     //  设置权重
                }
                //  储存至redis，中台使用的那份
                redisService.setCacheMap(hash, map);
                //  在储存一份iot使用
                ArrayList<String> keys = getKeys();
                for (String s : keys) {
                    if (s.endsWith(dataId)) {
                        String prefix = s.substring(0, s.lastIndexOf(":"));
                        redisService.setCacheMap(prefix+":"+hash,map);
                    }
                }
                /*String boxName = "";
                String[] originBox = handOutVo.getDataId().split("\\.");
                //  初始化boxName，将其设置为原始数据的盒子
                for (String s : keys) {
                    String[] split1 = s.split(":");
                    if (originBox[0].equals(split1[1])) {
                        boxName = split1[0];
                    }
                }
                //  将boxName设置为该设备所在的boxName
                for (String s : keys) {
                    String[] TempBoxNames = s.split(":");
                    if (TempBoxNames.length > 1 && TempBoxNames[1].equals(hash)) {
                        boxName = TempBoxNames[0];
                    }
                }
                redisService.setCacheMap(boxName + ":" + hash, map);*/
                //  数据库备份，防止数据丢失
                dataDistribution.setDistributionTarget(dataVo.getDataId());     //  设置分发目标
                //  设置分发类型
                if (handOutVo.getDataId() != null && (handOutVo.getDataId()).equals(dataVo.getDataId())) {
                    if (dataVo.getWeight() == null || dataVo.getWeight() == 0) {
                        dataDistribution.setAttributeType(AUTOMATIC);
                        continue loop;
                    } else {
                        dataDistribution.setAttributeType(MANUAL_OPERATION);
                    }
                } else {
                    dataDistribution.setAttributeType(MANUAL_OPERATION);
                }
//                for (IotDataDistribution distribution : dataDistributions) {
/*                    //  判断是否已经存在分发关系，如果已经存在，不在保存，只需更新权重
                    if (dataDistribution.getDataId().equals(distribution.getDataId()) && dataDistribution.getDistributionTarget().equals(distribution.getDistributionTarget())) {
                        double weight = dataDistribution.getWeight();
                        String dataId1 = distribution.getDataId();
                        String distributionTarget = distribution.getDistributionTarget();
                        dataDistributionMapper.updateWeight(weight, dataId1, distributionTarget);
                        //  更新Redis中数据
                        double newValue = Double.parseDouble(attributeValue.toString()) * weight;
                        HashMap<String, String> updateValueMap = new HashMap<>();
                        updateValueMap.put(key, String.valueOf(newValue));
                        redisService.setCacheMap(hash, updateValueMap);
                        redisService.setCacheMap(boxName, updateValueMap);
                        continue loop;
                    }*/
                //  如果分发目标已被分发，更新原始数据来源和权重
//                    if (dataDistribution.getDistributionTarget().equals(distribution.getDistributionTarget())) {
//                        return ResultVO.fail(distribution.getDataId() + "已经分发至" + dataDistribution.getDistributionTarget());
/*                        dataDistributionMapper.update(distribution, new LambdaQueryWrapper<IotDataDistribution>().eq(IotDataDistribution::getDistributionTarget, distribution.getDistributionTarget()));
                        //  更新Redis中的数据
                        double weight = dataDistribution.getWeight();
                        HashMap<String, String> updateMap = new HashMap<>();
                        double newValue = Double.parseDouble(attributeValue.toString()) * weight;
                        updateMap.put(key, String.valueOf(newValue));
                        redisService.setCacheMap(hash, updateMap);
                        redisService.setCacheMap(boxName, updateMap);
                        continue loop;*/
//                    }
//                }
                dataDistributionMapper.insert(dataDistribution);
            }
        } catch (NumberFormatException e) {
            e.printStackTrace();
            return ResultVO.fail("分发失败！");
        }
        return ResultVO.ok("分发成功！");
    }

    /**
     * 删除手动分发的数据
     *
     * @param dataId
     */
    @Override
    public ResultVO<String> dele(String dataId, String originalTarget) {
        try {
            List<IotDataDistribution> handouts = dataDistributionMapper.isHandout(dataId);
            if (handouts.size() > 1) {
                return ResultVO.fail("该数据已被分发，无法删除！");
            } else if (handouts.size() == 1) {
                //  如果自己分发给自己，可以删除,仅删除分发关系，无需处理redis中数据
                IotDataDistribution iotDataDistribution = handouts.get(0);
                if (iotDataDistribution.getDistributionTarget().equals(dataId) && iotDataDistribution.getDataId().equals(originalTarget)) {
                    //  删除数据库中分发记录
                    dataDistributionMapper.deleteById(iotDataDistribution);
                    return ResultVO.ok("删除成功！");
                }
            }
            List<IotDataDistribution> iotDataDistributions = dataDistributionMapper.getRelationship(dataId, originalTarget);
            ArrayList<Integer> ids = new ArrayList<>();
            for (IotDataDistribution iotDataDistribution : iotDataDistributions) {
                ids.add(iotDataDistribution.getId());
            }
            if (ids.size() > 0) {
                dataDistributionMapper.deleteBatchIds(ids);
            }
            int index = dataId.indexOf(".");
            String hash = dataId.substring(0, index);
            String key = dataId.substring(index + 1);
            String boxHash = "";
            ArrayList<String> keys = getKeys();
            for (String s : keys) {
                if (s.endsWith(hash)) {
                    boxHash = s;
                }
            }
            cacheUtils.deleteMap(hash, key);
            cacheUtils.deleteMap(boxHash, key);
        } catch (Exception e) {
            e.printStackTrace();
            return ResultVO.fail("删除失败！");
        }
        return ResultVO.ok("删除成功！");
    }

    /**
     * 将中台的数据组装为List<TopicUpVo.Content>集合
     *
     * @param list
     * @return
     */
    @Override
    public List<TopicUpVo.Content> groupContent(List<TopicUpVo.ConfigDetails> list) {
        List<TopicUpVo.Content> contents = new ArrayList<TopicUpVo.Content>();
        ArrayList<String> keys = getKeys();
        loop:
        for (TopicUpVo.ConfigDetails configDetails : list) {
            String dataId = configDetails.getDataId();
            int index = dataId.indexOf(".");
            String deviceName = dataId.substring(0, index);
            for (String key : keys) {
                if (key.endsWith(deviceName)) {
                    TopicUpVo.Content content = new TopicUpVo.Content();
                    int indexOf = key.indexOf(":");
                    String deviceId = key.substring(indexOf + 1);
                    TopicConfig topicConfig = mapper.getByDeviceId(deviceId);
                    if (contents.size() != 0) {
                        for (TopicUpVo.Content content1 : contents) {
                            if (content1.getDeviceId().equals(topicConfig.getDeviceId())) {
//                            if (content1.getBoxId().equals(topicConfig.getDeviceId())) {
                                List<TopicUpVo.ConfigDetails> config = content1.getConfig();
                                config.add(configDetails);
                                continue loop;
                            }
                        }
                        addNewContent(contents, configDetails, content, topicConfig);
                    } else {
                        addNewContent(contents, configDetails, content, topicConfig);
                    }
                    break;
                }
            }
        }
        return contents;
    }

    private void addNewContent(List<TopicUpVo.Content> contents, TopicUpVo.ConfigDetails configDetails, TopicUpVo.Content content, TopicConfig topicConfig) {
        content.setDeviceId(topicConfig.getDeviceId());
        content.setDeviceName(topicConfig.getDeviceName());
//        content.setBoxId(topicConfig.getDeviceId());
//        content.setBoxName(topicConfig.getDeviceName());
        content.setIp(topicConfig.getIp());
        content.setPort(topicConfig.getPort());
        content.setCpu(topicConfig.getCpu());
        content.setMomery(topicConfig.getMomery());
        ArrayList<TopicUpVo.ConfigDetails> details = new ArrayList<>();
        details.add(configDetails);
        content.setConfig(details);
        contents.add(content);
    }


    /**
     * @return
     * @Description 对list进行分页
     * @Param [nlist, pageNum]
     **/
    public static <T> List<List<T>> getPageData(List<T> nlist, int pageNum) {
        List<List<T>> result = new ArrayList<>();
        if (nlist == null || nlist.size() == 0) {
            return result;
        }
        if (pageNum < 1) {
            result.add(nlist);
            return result;
        }

        for (int i = 0; i < Math.ceil((double) nlist.size() / pageNum); i++) {
            List<T> tempList = nlist.stream().skip(i * pageNum).limit(pageNum).collect(Collectors.toList());
            result.add(tempList);
        }
        return result;
    }

}
